#include <log.h>
#include <base.h>
#ifndef WIN32
#include <execinfo.h>
#include <signal.h>
#endif
namespace mdk
{
#ifndef WIN32
    static BYTE signals_trace[] =
        {
            SIGILL,  /* Illegal instruction (ANSI).  */
            SIGABRT, /* Abort (ANSI).  */
            SIGBUS,  /* BUS error (4.2 BSD). (unaligned access) */
            SIGFPE,  /* Floating-point exception (ANSI).  */
            SIGSEGV, /* Segmentation violation (ANSI).  */
    };

#define BACKTRACE_SIZE 64
#ifdef __cplusplus
    extern "C"
    {
#endif
        static void debug_backtrace_dump(void)
        {
            int j, nptrs;
            void *buffer[BACKTRACE_SIZE];
            char **strings;

            nptrs = backtrace(buffer, BACKTRACE_SIZE);

            LOG_FATAL("stacktrace returned %d addresses", nptrs);

            strings = backtrace_symbols(buffer, nptrs);
            if (strings == NULL)
            {
                LOG_FATAL("backtrace_symbols");
                exit(EXIT_FAILURE);
            }

            for (j = 0; j < nptrs; j++)
                LOG_FATAL("\t[%02d] %s", j, strings[j]);

            free(strings);
        }

        static void debug_signal_handler(int sig_num,
                                         siginfo_t *info, void *ucontext)
        {

#ifdef _DEBUG
            char buff[64] = {0x00};
            sprintf(buff, "cat /proc/%d/maps", getpid());
            (void)system((const char *)buff);
#endif

            LOG_FATAL("=========>>>catch signal %s(%d) <<<=========",
                      strsignal(sig_num), sig_num);
            LOG_FATAL("Dump stack start...");
            debug_backtrace_dump();
            LOG_FATAL("Dump stack end...");
#ifdef _DEBUG
            signal(sig_num, SIG_DFL);
            raise(sig_num);
#else
        exit(EXIT_FAILURE);
#endif
        }

        extern "C" int debug_backtrace_init(void)
        {
            struct sigaction sa;
            (void)memset(&sa, 0, sizeof(struct sigaction));
            sa.sa_sigaction = debug_signal_handler;
            sa.sa_flags = SA_RESTART | SA_SIGINFO;
            int ret = 0;
            for (BYTE i = 0; i < (sizeof(signals_trace) / sizeof(signals_trace[0]));
                 ++i)
            {
                if (sigaction(signals_trace[i], &sa, NULL) != 0)
                {
#if _DEBUG
                    fprintf(stderr, "Failed to set signal handler for %s(%d)!\r\n",
                            strsignal(signals_trace[i]), signals_trace[i]);
#else
                LOG_ERROR("Failed to set signal handler for %s(%d)!",
                          strsignal(signals_trace[i]),
                          signals_trace[i]);
#endif
                    ret = -1;
                    break;
                }
            }
            return ret;
        }
#ifdef __cplusplus
    }
#endif
#endif
}